using System;
using System.Runtime.InteropServices;

namespace NTrace
{
    internal class TraceSessionHandle
    {
        private Int64 sessionHandle;

        public TraceSessionHandle(Int64 handle)
        {
            this.sessionHandle = handle;
        }

        internal class TraceSessionHandleMarshaler : ICustomMarshaler
        {
            private static readonly int SizeOfInt64 = Marshal.SizeOf(typeof(Int64));
            private static System.Collections.Generic.Dictionary<String, TraceSessionHandleMarshaler> instances = 
                new System.Collections.Generic.Dictionary<string,TraceSessionHandleMarshaler>();

            private TraceSessionHandleMarshaler()
            {
            }

            public static ICustomMarshaler GetInstance(String cookie)
            {
                if (!TraceSessionHandleMarshaler.instances.ContainsKey(cookie))
                {
                    TraceSessionHandleMarshaler temp = new TraceSessionHandleMarshaler();
                    TraceSessionHandleMarshaler.instances[cookie] = temp;
                }
                return TraceSessionHandleMarshaler.instances[cookie];
            }

            public void CleanUpManagedData(object ManagedObj)
            {
                // NOP
            }

            public void CleanUpNativeData(IntPtr pNativeData)
            {
                if (pNativeData != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pNativeData);
                }
            }

            public int GetNativeDataSize()
            {
                return TraceSessionHandleMarshaler.SizeOfInt64;
            }

            public IntPtr MarshalManagedToNative(object managedObject)
            {
                if (managedObject == null) return IntPtr.Zero;

                TraceSessionHandle target = managedObject as TraceSessionHandle;
                if (target == null) throw new ArgumentException("The supplied parameter must be a TraceSessionHandle.", "managedObject");

                IntPtr output = Marshal.AllocHGlobal(this.GetNativeDataSize());
                Marshal.WriteInt64(output, target.sessionHandle);
                return output;
            }

            public object MarshalNativeToManaged(IntPtr pNativeData)
            {
                if (pNativeData == IntPtr.Zero) throw new ArgumentNullException("pNativeData");

                Int64 handle = Marshal.ReadInt64(pNativeData);
                TraceSessionHandle output = new TraceSessionHandle(handle);
                return output;
            }
        }
    }
}
